package gui.event;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import gui.GameConstants;
import gui.drawers.BallDrawer;
import gui.drawers.Drawer;

import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JList;

import dal.MapStruct;
import dal.object.*;
import dal.object.grounds.Abyss;
import dal.object.rocks.Invisible;

/**
 * @author nosxp
 *	Contains and calculates the selected indexes when mouse click is performed on the map.
 * It's used in the map editor and for detecting collisions.
 */
public class HexGridListener extends MouseAdapter {
	private HexGrid hg;
	private JLayeredPane jLayers;
	private JComponent cmp;
	private MapStruct ms;
	private JList typeList;
	private Object selected;
	
	public HexGridListener(HexGrid hg, JLayeredPane jLayers, JList typeList){
		this.hg = hg;
		this.jLayers = jLayers;
		this.typeList = typeList;
		this.ms = hg.getMapStruct();
	}
	
	/**
	 * @param cmp
	 * 	the object that will gain focus when mousePressed is called.
	 */
	public void setFocusObject(JComponent cmp) {
		this.cmp = cmp;
	}
	
	/**
	 * @param i
	 * 	index of the of old object we want to change
	 * @param o
	 * 	the new object
	 */
    public void replaceObject(int i, Object o){
    	MapObject newMo = HexGrid.newInstace(o);
	    Vector<MapObject> v = ms.getVectorByType(newMo);
	    	
	    if(v != null){
	    	if(i >= 0 && i < v.size()){
		    	Drawer drawer = HexGrid.getDrawerByType(newMo, jLayers);
			    	
		    	if(newMo instanceof Card){
		    		((Card) newMo).finalizeCard();
		    		v.set(i, newMo);
		    	} else if(newMo instanceof Invisible) {
		    		((Invisible) newMo).setVisible(true);
		    		v.set(i, newMo);
		    	} else {
		    		v.set(i, newMo);
		    	}
		    	
	    		drawer.repaintAll();
	    	}
	    } else if(newMo instanceof Ball && i >= 0) {	// if vector index i is a valid index then matrix index i j are also valid
	    	BallDrawer bd = (BallDrawer) jLayers.getComponentsInLayer(GameConstants.BALL_LAYER)[0];
	    	bd.drawBall(hg.getHorizontalIndex(), hg.getVerticalIndex());
	    }
	    
	    jLayers.repaint();
    }
    
    /**
     * @param i
	 * 	index of the object which will be removed
	 * @param o
	 * 	type of the object
	 */
    public void removeObject(int i, Object o){
    	MapObject newMo = HexGrid.newInstace(o);
	    Vector<MapObject> v = ms.getVectorByType(newMo);
	    	
	    if(v != null){
	    	if(i >= 0 && i < v.size()){
		    	Drawer drawer = HexGrid.getDrawerByType(newMo, jLayers);
		    	
		    	if(newMo instanceof Ground){
		    		v.set(i, new Abyss());
		    	} else {
		    		v.set(i, null);
		    	}
		    	
	    		drawer.repaintAll();
	    	}
	    }
	    
	    jLayers.repaint();
    }
	
    /**
     * @param i
     * 	index of the selected element
     * @param replace
     * 	indicates that the selected object have to be replaced or removed
     */
    public void updateMap(int i, boolean replace){
    	if(selected != null){
			if(replace){
				replaceObject(i, selected);
			} else {
				removeObject(i, selected);
			}
		}
    }
    
    /**
     * Left click places the selected MapObject on the map.
     * Right click removes a MapObject from the map, depending on which type is selected (types: Rock, Ground, Ball, ...).
     */
	public void mousePressed(MouseEvent mouse) {
		selected = typeList.getSelectedValue();

		updateMap(hg.convertToIndex(mouse.getX(), mouse.getY()), mouse.getButton() == MouseEvent.BUTTON1);

		if(cmp != null && !cmp.hasFocus()){
			cmp.requestFocus();
		}
	}
}
